import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import model.ConnectionSingleton;
import model.Contient;
import model.ContientHome;
import model.Document;
import model.DocumentHome;
import model.Keyword;
import model.KeywordHome;
import model.Paragraphe;
import model.ParagrapheHome;
import model.Word;
import model.WordHome;

import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang3.tuple.Pair;
import org.hibernate.Query;
import org.hibernate.Session;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.filter.ElementFilter;
import org.jdom2.input.SAXBuilder;
import org.jdom2.xpath.XPathHelper;

import sun.org.mozilla.javascript.internal.JavaAdapter;


public class DocumentParser {
	
	
	
	private class WordRep implements Comparable<WordRep>{
		
		public String word;
		public Integer position;
		
		public WordRep(String s, Integer i) {
			word = s;
			position = i;
		}
		
		@Override
		public int compareTo(WordRep o) {
			return this.position.compareTo(o.position);
		}
		
		
	}

	private org.jdom2.Document doc;
	private Document document;
	private String fic;
	private DocumentHome documentHome;
	private HashMap<String, Integer> keywords;
	private List<String> stopList;
	private HashMap<String, Contient> contients;
	
	public DocumentParser(String filename,HashMap<String, Integer> keywords,HashMap<String, Contient> contients) {
		documentHome = new DocumentHome();
		stopList = new ArrayList<String>();
		this.contients = contients;
		readStopList();
		this.keywords = keywords;
		//on enregistre l'emplacement du fichier
		fic = filename;
		//recupération du fichier Competences
		File ficComp = new File(fic);
		try {
			//cree l'arbre DOM de ce document
			doc = new SAXBuilder().build(ficComp);
		} catch (JDOMException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	//crée les informations sur une personne à partir de l'arbre DOM d'un CV d, et de son nom de fichier n et met à jour le fichier Competences.xml
	public void parserDocument() throws Exception{
		Element elem = doc.getRootElement();
		Element titre = null;
		String documentName = this.fic.substring(21);
		document = new Document(documentName,null);
		documentHome.persist(document);
		titre = doc.getRootElement().getDescendants(new ElementFilter("TITRE")).next();
		this.parserElement(elem,titre);
	}
	
	//parser récursivement les éléments du document
	private void parserElement(Element elem,Element title) throws Exception{
		Element sub = null;
		if(elem == null){
			throw new Exception("Probleme");
		}
		if(elem.getName().equals("P")){
			this.parserParagraphe(elem, title);
		}
		else{
			List<Element> children = elem.getChildren();
			for (Element child : children) {
				this.parserElement(child,title);
			}
		}
		
	}
	
	private Element getParentSection(Element elem) {
		Element section = null;
		Element parent = elem.getParentElement();
		if(parent != null && parent.getName() == "SEC"){
			section = parent;
		}
		else{
			if(parent != null){
				section = getParentSection(parent);
			}
		}
		return section;
		
	}
	
	private Element getSectionSubtitle(Element section) {
		Element subtitle = null;
		Element child = section.getChild("SOUS-TITRE");
		if(child != null ){
			subtitle = child;
		}
		return subtitle;
		
	}
	
	//extrait les infos d'un paragraphe et les stocke dans la base
	private void parserParagraphe(Element elem,Element title) throws Exception{
		Element section = getParentSection(elem);
		Element subtitle = null;
		if(section != null){
			subtitle = getSectionSubtitle(section);
		}
		String xpath = "";
		try{
			xpath =  XPathHelper.getAbsolutePath(elem.getContent(0));
		}
		catch(IndexOutOfBoundsException e){
			
		}
		xpath = xpath.replaceAll("([^\\]])/", "$1[1]/");
		xpath = xpath.replaceAll("/text\\(\\)", "");

		String paragraphe_text = getParagrapheText(elem);
		
		ParagrapheHome paragrapheHome = new ParagrapheHome();
		KeywordHome keywordHome = new KeywordHome();
		ContientHome contientHome = new ContientHome();
		WordHome wordHome = new WordHome();
		String[] words_temp = paragraphe_text.split("[\\s|,|`|‘|\\.|;|\\?|:|\\-|\\*|°|\\/|\\+|\\$|£|€|\\d|\\!|'|\"|«|»|\\[|\\]|\\(|\\)|~|\\{|\\}]+");
		List<String> words = new ArrayList<String>();
		for (String w : words_temp) {
			String word = w;
			boolean isint = false;
			try{
				Integer.parseInt(word);
				isint=true;
			}
			catch(Exception e){
				isint = false;
			}
			if(!isint && word.length() >1 && notInStopList(word)){
				words.add(word);
			}
		}
		Paragraphe paragraphe = new Paragraphe(document, xpath,words_temp.length,paragraphe_text,null,null);
		paragrapheHome.persist(paragraphe);
		HashMap<String,ArrayList<WordRep>> map = new HashMap<String,ArrayList<WordRep>>();
		int i = 0;
		for (String word : words) {
			String trString = "";
			if(word.length() >= 6){
				trString = word.substring(0,6).toUpperCase();
			}
			else{
				trString = word.toUpperCase();
			}
			if(map.containsKey(trString)){
				map.get(trString).add(new WordRep(word, i));
			}
			else{
				map.put(trString,new ArrayList<WordRep>());
				map.get(trString).add(new WordRep(word, i));
			}
			i++;
		}
		for (String word : map.keySet()) {
			Contient contient = null;
			if(keywords.get(word) == null){
				Keyword keyword = new Keyword(word,1,null);
				try{
					keywordHome.persist(keyword);
				}
				catch(Exception e){
					//e.printStackTrace();
					//throw new Exception("");
				}
				keywords.put(word,keyword.getIdKeyword());
				contient = new Contient(keyword,paragraphe,"paragraphe",1,null);
				contientHome.persist(contient);
				contients.put(keyword.getIdKeyword()+"-"+paragraphe.getIdPara(), contient);
			}
			else{
				Keyword existing_keyword = keywordHome.findById(keywords.get(word));
				existing_keyword.setNbParagraphes(existing_keyword.getNbParagraphes()+1);
				if(contients.get(existing_keyword.getIdKeyword()+"-"+paragraphe.getIdPara()) == null){
					contient = new Contient(existing_keyword,paragraphe,"paragraphe",1,null);
					contientHome.persist(contient);
					contients.put(existing_keyword.getIdKeyword()+"-"+paragraphe.getIdPara(), contient);
				}
				else{
					contient = contients.get(existing_keyword.getIdKeyword()+"-"+paragraphe.getIdPara());
					contient.setFrequence(contient.getFrequence()+1);
				}
			}
			ArrayList<WordRep> arr = map.get(word);
			for (WordRep full_word : arr) {
				Word w = new Word(paragraphe,null,contient,null,full_word.word,full_word.position,null,null);
				wordHome.persist(w);
			}
			
		}
		String title_text = "";
		if(title != null){
			title_text = title.getText();
		}
		map.clear();
		String[] title_words = title_text.split("[\\s|,|`|‘|\\.|;|\\?|:|\\-|\\*|°|\\/|\\+|\\$|£|€|\\d|\\!|'|\"|«|»|\\[|\\]|\\(|\\)|~|\\{|\\}]+");
		for (String w : title_words) {
			String word = w.toUpperCase();
			boolean isint = false;
			try{
				Integer.parseInt(word);
				isint=true;
			}
			catch(Exception e){
				isint = false;
			}
			if(!isint && word.length() >1 && notInStopList(word)){
				String trString = "";
				if(word.length() >= 6){
					trString = word.substring(0,6);
				}
				else{
					trString = word;
				}
				if(map.containsKey(trString)){
					map.get(trString).add(new WordRep(word, i));
				}
				else{
					map.put(trString,new ArrayList<WordRep>());
					map.get(trString).add(new WordRep(word, i));
				}
			}
			i++;
		}
		for (String word : map.keySet()) {
			Contient contient = null;
			if(keywords.get(word) == null){
				Keyword keyword = new Keyword(word,1,null);
				try{
					keywordHome.persist(keyword);
				}
				catch(Exception e){
					//e.printStackTrace();
					//throw new Exception("");
				}
				keywords.put(word,keyword.getIdKeyword());
				contient = new Contient(keyword,paragraphe,"title",1,null);
				contientHome.persist(contient);
				contients.put(keyword.getIdKeyword()+"-"+paragraphe.getIdPara(), contient);
			}
			else{
				Keyword existing_keyword = keywordHome.findById(keywords.get(word));
				existing_keyword.setNbParagraphes(existing_keyword.getNbParagraphes()+1);
				if(contients.get(existing_keyword.getIdKeyword()+"-"+paragraphe.getIdPara()) == null){
					contient = new Contient(existing_keyword,paragraphe,"title",1,null);
					contientHome.persist(contient);
					contients.put(existing_keyword.getIdKeyword()+"-"+paragraphe.getIdPara(), contient);
				}
				else{
					contient = contients.get(existing_keyword.getIdKeyword()+"-"+paragraphe.getIdPara());
					contient.setFrequence(contient.getFrequence()+1);
				}
			}
			ArrayList<WordRep> arr = map.get(word);
			for (WordRep full_word : arr) {
				Word w = new Word(paragraphe,null,contient,null,full_word.word,full_word.position,null,null);
				wordHome.persist(w);
			}
			
		}
		String subtitle_text = "";
		if(subtitle != null){
			subtitle_text = subtitle.getText();
		}
		map.clear();
		String[] subtitle_words = subtitle_text.split("[\\s|,|`|‘|\\.|;|\\?|:|\\-|\\*|°|\\/|\\+|\\$|£|€|\\d|\\!|'|\"|«|»|\\[|\\]|\\(|\\)|~|\\{|\\}]+");
		for (String w : subtitle_words) {
			String word = w.toUpperCase();
			boolean isint = false;
			try{
				Integer.parseInt(word);
				isint=true;
			}
			catch(Exception e){
				isint = false;
			}
			if(!isint && word.length() >1 && notInStopList(word)){
				String trString = "";
				if(word.length() >= 6){
					trString = word.substring(0,6);
				}
				else{
					trString = word;
				}
				if(map.containsKey(trString)){
					map.get(trString).add(new WordRep(word, i));
				}
				else{
					map.put(trString,new ArrayList<WordRep>());
					map.get(trString).add(new WordRep(word, i));
				}
			}
			i++;
		}
		for (String word : map.keySet()) {
			Contient contient = null;
			if(keywords.get(word) == null){
				Keyword keyword = new Keyword(word,1,null);
				try{
					keywordHome.persist(keyword);
				}
				catch(Exception e){
					//e.printStackTrace();
					//throw new Exception("");
				}
				keywords.put(word,keyword.getIdKeyword());
				contient = new Contient(keyword,paragraphe,"subtitle",1,null);
				contientHome.persist(contient);
				contients.put(keyword.getIdKeyword()+"-"+paragraphe.getIdPara(), contient);
			}
			else{
				Keyword existing_keyword = keywordHome.findById(keywords.get(word));
				existing_keyword.setNbParagraphes(existing_keyword.getNbParagraphes()+1);
				if(contients.get(existing_keyword.getIdKeyword()+"-"+paragraphe.getIdPara()) == null){
					contient = new Contient(existing_keyword,paragraphe,"subtitle",1,null);
					contientHome.persist(contient);
					contients.put(existing_keyword.getIdKeyword()+"-"+paragraphe.getIdPara(), contient);
				}
				else{
					contient = contients.get(existing_keyword.getIdKeyword()+"-"+paragraphe.getIdPara());
					contient.setFrequence(contient.getFrequence()+1);
				}
			}
			ArrayList<WordRep> arr = map.get(word);
			for (WordRep full_word : arr) {
				Word w = new Word(paragraphe,null,contient,null,full_word.word,full_word.position,null,null);
				wordHome.persist(w);
			}
		}
	}

	private String getParagrapheText(Element elem) {
		StringBuilder text = new StringBuilder();
		if(elem.getChild("LISTE") != null){
			Element liste = elem.getChild("LISTE");
			for (Element item : liste.getChildren()) {
				text.append(item.getText()+" ");
			}
		}
		else{
			text.append(elem.getText());
		}
		return text.toString();
	}

	private boolean notInStopList(String word) {
		boolean not_in = true;
		for (String stop_word : stopList) {
			if(word.compareToIgnoreCase(stop_word) == 0){
				not_in = false;
			}
		}
		return not_in;
	}
	
	private void readStopList() {
		try{
			  // Open the file that is the first 
			  // command line parameter
			  FileInputStream fstream = new FileInputStream("documents/stopliste.txt");
			  // Get the object of DataInputStream
			  DataInputStream in = new DataInputStream(fstream);
			  BufferedReader br = new BufferedReader(new InputStreamReader(in));
			  String strLine;
			  //Read File Line By Line
			  while ((strLine = br.readLine()) != null){
				  stopList.add(strLine);
			  }
			  //Close the input stream
			  in.close();
			}catch (Exception e){//Catch exception if any
				  System.err.println("Error: " + e.getMessage());
			}
		
	}
}
